fix(runtime): narrow the block table, read Codex tool output, re-derive the shape counts - #229
Merged
Merged
Conversation
…ve the shape counts DRC-4269, the correctness and comment-accuracy half. - `_derive_block` no longer fires on quoted prose. `not permitted`, `permission denied` and `waiting for your` supplied 4 of the 7 blocks the local Claude corpus publishes and every one sat in a quoted or fenced span; two hit the 200-character cap with the trigger truncated away. They are replaced by first-person forms, and an indicator now has to end on a word boundary so `waiting for you` stops matching the possessive. - `spacedock.tool_result_text` learns Codex's spelling. It read only Claude's and Pi's, so the observer's stage half was structurally unreachable there: 0 of 458 local rollouts yielded a boot envelope, and 10 do now. - The observer's head and tail windows are cut apart on byte offsets, which makes the dedup fallback positional. `payload.id` is absent on 76.4% of the Codex user records inside those windows, so the key fell through to the message text and a repeated prompt kept its oldest position. - A clipped goal keeps its ellipsis: the scrub ran at the cap, not cap + 1. - A leading U+FEFF / U+200B / U+2060 no longer defeats all three `injected_prompt` branches at once. That was the one degenerate class that failed open. - Every count in the prompt-shape comment block is re-derived by `scripts/derive_prompt_shapes.py`, committed here. It prints counts and shape names only, never prompt text, and its guard and test say so. - Three wrong figures in `transcripts.py` corrected against fresh measurement, and the developer-tag counts relabelled as the leading counts they now are. Signed-off-by: Jared Scott <jared.scott@variable.team>
…split sync-docs pass for the correctness branch. S-6 in design-spacedock.md carries the measured Codex payload shapes and why a function_call's arguments are not tool output; the observer and spacedock rows in the architecture map pick up the window split and the narrowed block table; CONTRIBUTING.md documents the new derivation script and its no-prompt-text guard. Signed-off-by: Jared Scott <jared.scott@variable.team>
Contributor
CoverageThreshold: |
…our figures
One blocking finding from an adversarial review, plus the four numbers this
branch introduced that its own review then measured as wrong. Correcting those
here rather than filing them: a PR whose subject is wrong figures in comments
should not ship four new ones, and the blocking fix already forced the round.
B2, the blocker. `_TAG_NAME_RE` admitted 40 characters while the comment three
lines above justifying the bound said "the longest name in any of `records.py`'s
vocabularies is 21 characters" -- which is right, `subagent_notification`. So a
prompt opening with `<` plus a 40-character `[A-Za-z0-9_-]` run terminated by
whitespace reached stdout verbatim through the unlisted-tag branch, falsifying
this module's own docstring and CONTRIBUTING.md on the one script whose job is
to read every prompt in the store. The existing negative case was 44 characters,
one class above the bound, so it proved rejection at 44 and never probed 40.
Lowered to 24. The longer vocabulary entries are prose prefixes that reach
stdout through `_safe_label`'s membership clauses, not through this pattern, so
narrowing it cannot reject them. The discovery affordance survives: over 3,774
local Claude transcripts there are exactly 2 distinct unlisted leading tag names
occurring more than once, both 21 characters or shorter, and 0 occurrences of
the over-long aggregate. Boundary now pinned at 21, 24 and 25, plus a case
proving an over-long name aggregates rather than printing itself.
B1. Decision S-6 said 18 rollouts carry a boot envelope and the docstring said
12 arrive on a `function_call_output`. Measured with the shipped
`boot_records` over the collector's own glob: 14 files carry an envelope the
reader PARSES (9 `function_call_output`, 6 `custom_tool_call_output`, one file
both), 50 records, 43 of them on `function_call_output`. 18 and 12 count files
whose record holds a `{"command"` CANDIDATE object, parsed or not -- a different
question, now recorded as such so nobody re-derives it and reads it as a
regression.
B3. The "599 of 784" id-absence figure was measured on the `head + read_tail`
concatenation this same commit replaces with disjoint windows, so it was a count
taken on the double-counting instrument whose double-counting the commit fixes.
The disjoint windows give 500 of 655. Both are 76.3%, which is the point worth
making, so the docstring now gives both and names the instrument.
B4. `channel` is the fourth `_turn_signal`-refused entry and was the only one
unmarked, while the header's total needs it: 1,065 + 621 + 223 + 8 = 1,917.
B5. The branch deleted the denominator that made "~95%" correct. Over the
population the sentence then named it was 82.9%. Restored as 294 of 305 release
builds (96.4%), with the prerelease split stated: folding the 0.145.0-alpha
files back in gives 296 of 357, because `phase == "commentary"` reached 1 of 51
alpha files. A prerelease is the one population where the shape was mid-move.
Refs DRC-4269
Signed-off-by: Jared Scott <jared.scott@variable.team>
One conflict, in `tests/test_observer.py`, and it was the shape AGENTS.md warns about: both sides added a test at the same insertion point, so each side's hunk was correct for a tree that no longer exists. Resolved as a union rather than a choice, because all three tests are wanted: - `test_the_first_person_replacements_still_report_a_real_block` (this branch, the 1.1 narrowing) - `test_a_rejected_indicator_hit_does_not_hide_a_later_real_one` (this branch) - `test_a_block_past_the_publish_cap_is_still_found` (from #230, the `extract_text` cap regression) The import line conflicted for the same reason and needs all three names: `runtime_io` from this branch, `records` from #230. Verified on the merged tree rather than on the resolution: 1,934 dashboard tests OK and 192 scripts tests OK, ruff, ruff format, mypy --strict and validate_plugins all clean. Signed-off-by: Jared Scott <jared.scott@variable.team>
gcko
added a commit
that referenced
this pull request
Aug 27, 2026
AGENTS.md's Parallel Work section says to leave this marker alone per branch and stamp it once from main after the merges, naming what the range actually covers. Three parallel branches just landed, so this is that stamp. 11730b5..0f9d086 is eleven commits: the v0.16.0 release, the five PRs that built the instruction line and the redaction filter (#220, #222, #223, #225, #226), the review-calibration and CI-detector change (#227), and the three DRC-4269 follow-ups that cleared the deferred-findings backlog (#228, #229, #230). Each of those PRs carried its own doc updates, and the three DRC-4269 branches deliberately did not touch this line so they could not collide on it. What this stamp vouches for is that range as a whole: the design docs, SECURITY.md and the runtime architecture module map were reconciled against the code inside the PRs that changed it, and several figures in them were re-derived rather than carried forward. Signed-off-by: Jared Scott <jared.scott@variable.team>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The correctness and comment-accuracy half of DRC-4269. Every figure below was re-measured on the
local store rather than carried over; where my number disagrees with the finding's, I shipped mine
and say how it was measured. Two items are refuted with evidence and were not implemented.
1.1
_derive_blockfires on quoted prose — FIXEDRe-measured across the whole local Claude corpus (3,774 transcripts, 2,828 with an assistant
message): the shipped table published 7 blocks. Structurally:
i'm blockedwaiting for you(bare)waiting for youmatchingyour…not permittedpermission deniedSo 4 of 7 were the three phrases the finding names, all in a quoted or fenced span, two rendering
with no block language in the visible text.
waiting for yourcould not be fixed on its own:waiting for youis a prefix of it and is checkedfirst, so the listed
waiting for yourentry was dead code and giving it the first-persontreatment would have changed nothing. The fix is therefore two parts:
i'm not permitted,i am not permitted,i don't have permission,i do not have permission,i'm waiting for your,i am waiting for your), which match 0 records today;_BLOCK_TRAILING_RE), which is what makes barewaiting for youstop matching the possessive, and_indicator_hitscans past a rejected hit soan earlier possessive cannot hide a later genuine hand-off.
Corpus effect: 7 blocks to 3, and the 3 are the clean ones above.
test_ordinary_reporting_prose_is_not_a_blockgains four lines covering the three phrases plus theprefix case. Two new tests pin the other direction:
test_the_first_person_replacements_still_report_a_real_blockandtest_a_rejected_indicator_hit_does_not_hide_a_later_real_one.1.2 The observer's stage half is unreachable on Codex — FIXED, with a measured shape
tool_result_textreadrecord["message"], which a Codex rollout does not have. Measured beforethe change: 0 of 458 local rollouts yielded a boot envelope. After: 10.
The payload shape was verified against real rollouts rather than guessed. Both spellings and both
value shapes are measured:
outputis a stringoutputis a list of{type, text}blocksfunction_call_outputcustom_tool_call_output23 rollouts name a
definition_diranywhere; 18 carry a boot envelope on one of those two payloadtypes; 10 have it inside the
spacedock_boot_scan_byteshead window.The provenance rule is preserved: only a tool OUTPUT counts. A
function_call'sargumentsfieldcarries the same JSON on the way in and is refused, which is the same distinction Pi's
toolResultrole gate makes. Three new tests cover the four shapes, the negative twin, and the untrusted-value
guards.
docs/design-spacedock.mdgains decision S-6 with the numbers and the rejected alternative(
event_msg/item_completed, which turns out to beCommandExecutionitems whosedefinition_dirmention is the command line rather than its output, carrying 0 envelopes).
1.3 The Codex dedup key degrades to text — FIXED
Measured over the whole rollout store, inside the observer's own head and tail windows:
599 of 784 Codex user-message records (76.4%) carry no
payload.id. (The finding said 76.6%;mine is 76.4% and the instrument is in the report notes.)
The fallback is now positional, and that needed the windows to stop overlapping first: they overlap
completely on any file the 400 KB tail read swallows whole, so a purely positional key would have
double-counted every record.
_window_linescuts them apart on byte offsets, after which position isa genuine identity and the id key is left doing the one job it is good at, collapsing a resumed
transcript's replayed block.
tests/_codex_messagetakespayload_id=Noneand writes the record with noidkey at all.test_a_repeated_codex_prompt_with_no_payload_id_keeps_the_newestis the regression;test_a_replayed_record_is_still_deduped_by_its_own_idguards the other side.One sub-claim refuted: there is no 72.6% figure anywhere in the tree (
grep -rn 72.6finds onlytest digests). The
_dedup_keydocstring's inherited figure is "0 of 8,312 Claude and 0 of 14,389Codex records carry a top-level
id", which is a different claim and still true. The docstring nowcarries the measured 76.4% with its population named.
1.4
instruction_from's unconditionaltitle_is_promptsuppression — REFUTED, not implementedThe premise is that replacing the Python suppression with the frontend echo test would surface the
withheld characters. It would not. Measured by running
instruction_fromboth ways over all 458rollouts and evaluating
nextInstructionEchoes(fromweb/next/next-boot.js) in Python:All 213 new lines are suppressed, including the 151 clipped-title rows that are exactly the
population the finding wanted surfaced.
nextInstructionEchoes's second clause(
head.endsWith("…") && line.startsWith(head.slice(0, -1))) is written for that case and isdeliberate: line 1 clips at 80 and line 2 at 140, so one prompt reaches them as two strings.
Implementing the Python half alone would emit 213 payload fields that render nowhere and put the
same policy in two places, which is the opposite of the item's stated point. I did not implement it.
The
instruction_fromdocstring now records the measurement so the finding is not re-derived.web/follow-up to file (a sibling owns that file, so it is not in this PR): relaxnextInstructionEchoesso a strictly longer extension of a clipped title is kept rather thansuppressed, then delete
title_is_prompt. That is the change that surfaces the withheld characters,and it belongs in the PR that owns
web/.3.1 The window test is vacuous and the route test is Pi-shaped — FIXED
test_the_head_window_and_the_tail_window_are_both_readnow asserts the block as well as thegoal. The goal lives only in the head and the block only in the tail, so it fails when either
window is not read.
test_the_tail_assertion_is_load_bearingcommits the falsification: withread_tailstubbed to[]the goal survives and the block disappears, so if a later edit makesthe block reachable from the head, that test goes red rather than the first one going quiet.
/api/observeroute test wrote a Pi-shapedtype: "message"record into the Claude store,a shape that occurs 0 times in 3,774 real Claude transcripts. It now writes Claude-shaped records
and asserts the block too.
test_the_route_answers_for_a_codex_rolloutis new: a realistic rollout withsession_meta,id-less
response_itemmessages, the resolver matching onsession_metarather than a filenamestem, and the sidecar written.
Non-vacuity was proved by breaking the code and watching the intended test go red, one edit at a
time (7 for 7). The exact edits are in the report notes.
3.3 No committed derivation script — FIXED
scripts/derive_prompt_shapes.pyre-derives every count in the harness-injected-prompt commentblock from a store the caller points it at. Every figure now in
records.pyis one of its outputs.It prints counts and shape names only, never prompt text. That constraint is in the module
docstring and enforced by
_safe_label, a whitelist rather than a filter: a label must be a shortmarkup tag name, a literal already present in
records.py's own vocabularies, or one of a fixed setof column headings, and anything else raises
UnsafeLabelError. A tag name longer than the bound isaggregated under a structural label rather than printed, and rather than raised on, so a weird
transcript cannot make the script unusable. Discovering a new prose prefix is deliberately out of
scope, because it cannot be done without printing prose.
scripts/tests/test_derive_prompt_shapes.pyseeds a distinctive prompt into a fixture store andasserts the whole stdout carries none of it, asserts the guard rejects prompt-shaped labels, and
asserts the script's
_turn_signalreimplementation agrees with the real one on seven recordshapes. Wired into the pre-PR list in
AGENTS.mdand into both coverage blocks inquality-gate.yml; the script itself reports 89.3% coverage.4.1 Three wrong figures in
transcripts.py— FIXED, with my own measurementscodex_instructionwalk cost_codex_walktimed over all 458 rolloutsitem_completed/AgentMessagereachphase == "commentary"narrowing the code applies takes it to 79UserMessageas the only prompt pathThe finding said 83.1 ms and 78 of 88; I measure 84 ms and 79 of 89. The docstring now separates the
two AgentMessage numbers, because conflating "the shape exists" with "the code reads it" was the
defect. The
UserMessagebranch is kept and now says plainly that it changes no reading today.4.8 Comment-block provenance — FIXED
The block header now names the exact record population behind each half:
event_msg/user_messagetexts and 1,734response_itemmessage texts with
role: "user", across 458 rollouts. That union double-counts: 974 of the1,007
event_msgprompts have a matchingresponse_item. So the counts are occurrences of ashape, not prompts, and the comment says so. (Equality matching scores 850; the 974 uses a
400-character head match, because
extract_textcaps a block-list join at 2,000 characters whilean
event_msg'smessageis one uncapped string.)response_itemmessage texts withrole: "developer".One sub-claim shipped differently. The finding says "six Claude entries totalling 5,367
occurrences count records
_turn_signalalready refuses". Running the realrecords._turn_signalover every leading-tag record gives four entries and 1,917 of the 5,393 occurrences:
local-command-caveat1,065 of 1,065,local-command-stdout621 of 621,system-reminder223 of227,
channel8 of 8.task-notification,teammate-message,bash-input,bash-stdoutandlocal-command-stderrare refused 0 times. I shipped my numbers.4.9 Developer-tag counts are containment counts — FIXED
Confirmed exactly. Leading versus containment on the same corpus:
permissionsmulti_agent_modeskills_instructionscollaboration_modeapp-contextapps_instructionsplugins_instructionsThe documented set was a mix of both, which is exactly how
collaboration_modelooked small. Thecounts are now leading counts, labelled as such. The two that lead 0 records are kept for the
documented asymmetry (an unlisted tag renders markup as a person's words; a listed one that never
arrives costs nothing) but are labelled
0 leading (N contained) — defensive onlyrather than leftlooking measured.
turn_abortedleads 52 developer-role records and is noted on its user-set entry.4.10 The
[Imagearithmetic — FIXEDThree populations, not one plus an anecdote:
[Image: source: …][Image source: …][Image #N]The old comment said "385 of 386" and called
[Image source:"the 386th". It is a separatepopulation of 9, and the reason the separator is a character class is
[Image #N], where a spacefollows
Image. (The finding said 386, 9, 134/133; my corpus is one record larger on two of thethree.) The Codex
<image>figure reproduces exactly at 36, all carrying operator text.4.11
Warmup— 97 over a stated denominator, and subagent-onlyI measure 97, not 85, over the Claude population the block header names. The comment now states
that denominator instead of leaving it implied, and adds the facts that matter: all 97 are
isSidechainrecords, 0 arrive on a Codex rollout, and_turn_signalalready refuses 12 of the 97.That is likely where the finding's 85 comes from, but I did not want to ship a number I could not
reproduce, so the comment carries mine with its population named.
4.12 Pointer comments for two duplications — FIXED
_turn_signal's hardcoded("<local-command-stdout>", "<local-command-caveat>")now carries anote that both names are also in
_CLAUDE_USER_TAGS, that this is a record rule and that is atext rule, that the tag set covers seven further names this must not refuse, and that a name added
here belongs in both.
observer._is_generic_openerandrecords.injected_promptpoint at each other, with the reasonthey are separate (a goal rule versus a record rule) written once in the observer.
Nits
Fixed:
str.strip()removeswhitespace and none of these is whitespace to Python, so one character in front of a record
defeated the leading-tag regex, the prose prefixes and the whole-body set at once, and
injected_promptanswered "the operator said this" about harness machinery.strip_prompt_wrappersnow trims
_UNSAFE_CHARSminus C0/DEL, plus U+2060 and U+FEFF; U+200C and U+200D stay out becausethey are orthographic. Test covers six lead shapes across three branches plus the other direction.
_derive_goal_deterministicscrubbed at the cap, notcap + 1, so a hard-cut goal lost its
…. Measured: 8 of the 1,295 goals the local Claudecorpus publishes, of which 269 clip at all. (The nit said 11 of 1,469.) Same
+ 1and same reasonas
records.instruction_line.shorten_pathsrunning undocumented. One clause added where the goal is rendered. No number,because I did not measure the 69 and would not vouch for it.
_SHARED_MESSAGE_HARNESS. The comment now says the dict miss is the mechanism rather than anaccident, and that the Droid half of the name is aspirational because
resolve_transcriptanswersfor claude, codex and pi only.
Skipped, with the reason:
would newly reject an operator writing "warmup the cache", which is the false positive
_INJECTED_PROMPTSis matched-whole to avoid. 0 corpus incidence either way.body that matches
_PROMPT_LEADING_TAG_REstarts with<, and no listed prose prefix orwhole-body literal starts with
<. The branch cannot change an answer.[Image processing]peeled as a marker. Narrowing the wrapper regex to the three measuredspellings risks dropping an unmeasured marker variant, and the failure mode of that (publishing a
marker as a goal) is the one this code exists to prevent. 0 corpus incidence.
extract_textcaps at 2,000characters, 42 ms at 8,000 stacked markers. Not worth the complexity.
<command-args>branch. I could not identify a specific defect from thedescription without guessing which regex and which branch were meant, and there is already a
fixture exercising an empty
<command-args>. Not acted on rather than acted on speculatively.NO_GOAL_REASONnaming a never-occurring condition. A provenance note only, and I would havehad to run another corpus pass to vouch for a number. The docstring already explains the sentinel
bounds the model.
/api/healthorwrite_state. Scope creep, as the finding allows.Verification
Full pre-PR suite run once on this tree.
ruff check,ruff format --check,mypy --strict,lint_embedded.py --allow-missing-node,validate_plugins.py,bump_version.py --currentallclean. Dashboard suite 1,919 tests OK (1 skipped, pre-existing). Scripts modules 190 tests OK.
Coverage total 90.7%,
fail_under73. No manifest file is touched, soversion-guardhas nothingto see.